#include "stm32f10x.h"
#include "delay.h"
#include "led.h"
#include "ESP8266.h"

/* 
    需要引入RTC、BKP、PWR固件库
    RTC为实时时钟，是一个独立定时器。RTC的时钟默认来自外部低速时钟(LSE)32.768KHz
    其模块及时钟配置系统(RCC_BDCR寄存器)都在后备区域，即使断电也不会改变。复位后为防止误操作，RTC会开启后备区域(BKP)写保护
    
    BKP备份寄存器为42个16位的寄存器，可以存储84字节的数据，处于后备区域。
    通过设置寄存器RCC_APB1ENR的PWREN和BKPEN位，使能电源和后备时钟。通过设置PWR_CR的DBP位，使能RTC和后备寄存器的访问。

    RTC在后备区中有预分频器、32位计数器(向下);后备区外有控制寄存器
    RTC预分频器中有装载寄存器(RTC_PRL)、余数寄存器(RTC_DIV)，分频系数将做为RTC_DIV的重装载值存入RTC_PRL,RTC_DIV将以RTCCLK时钟(默认为LSE)为频率向下计数，可以作为更精确的计时。
    RTC预分频器最终输出TR_CLK时钟，一般频率设置为1Hz用于计秒，而TR_CLK每周期都会产生信号，一般为一秒一周期。
    32位计数器中有RTC计数器寄存器(RTC_CNT)、RTC闹钟寄存器(RTC_ALR)，计数器能从初始值向下计数，溢出时产生溢出信号，当计数器的值与闹钟寄存器中的值相同时触发闹钟信号。
    RTC控制寄存器主要是更据秒信号、溢出信号、闹钟信号产生中断

    RTC控制寄存器(RTC_CRH,RTC_CRL): 
        H0位为秒中断允许;H1位为闹钟中断允许;H2位为溢出中断允许;
        L0~L2位分别为秒标志位(SECF)、闹钟标志位(ALRF)、溢出标志位(OWF)，当产生秒信号时置1，只能软件置0硬件置1;
        L3位为寄存器同步位(RSF)，每当RTC_CNT和RTC_DIV由软件更新时或APB1时钟停止/复位后被软件置0，必须等待其由硬件置1，表示寄存器同步后才能对寄存器进行读操作;
        L4位为配置标志(CNF),对寄存器写操作前必须置1，操作结束后必须置0否则不执行;L5位为RTOFF，由硬件置1时表示上次操作结束，只有上一次操作结束后才能再次对寄存器进行写操作
    RTC预分频装载寄存器(RTC_PRLH[15(3):0],RTC_PRLL[15:0]):  H[3:0]位为预分频系数高4位; L[15:0]位为预分频系数低16位 
    RTC预分频余数寄存器(RTC_DIVH[15(3):0],RTC_DIVL[15:0]):  H[3:0]位为预分频余数高4位; L[15:0]位为预分频余数低16位 
    RTC计数器寄存器(RTC_CNTH[15:0],RTC_CNTL[15:0]):  H[15:0]位为计数器高16位; L[15:0]位为计数器低16位 
    RTC闹钟寄存器(RTC_ALRH[15:0],RTC_ALRL[15:0]):  H[15:0]位为计数器高16位; L[15:0]位为计数器低16位 
*/

//设置时间
void RTC_SetTime(u16 year,u16 mouse,u16 day,u16 hour,u16 min,u16 sec){
	int r=0;
	int m[12]={31,28,31,30,31,30,31,31,30,31,30,31};
	u32 res=0;
	if ((year-1972)%4==0) r=(year-1972)/4;
	else r=((year-1972)/4)+1;
	res+=(r+(year-1970)*365)*24*60*60;
	if (year%4==0&&mouse>2) res+=24*60*60;
	res+=(day-1)*24*60*60+(hour)*60*60+(min)*60+sec;
	for(--mouse;mouse>0;mouse--){
		res+=m[mouse-1]*24*60*60;
	}
	
	RTC_SetCounter(res);
	RTC_WaitForLastTask();
}

void RTC_GetTime(void){
	u32 s=RTC_GetCounter();
	//char *res;
	int m[12]={31,28,31,30,31,30,31,31,30,31,30,31};
	u32 ss=31536000; u32 sb=31622400; u32 sd=86400;
	int year=0; int mon=1; int day=1; int hour=0; int min=0; int sec=0;
	s-=(2*ss);
	year+=1972+4*(s/(ss*3+sb));
	s%=(ss*3+sb);
	if (s>sb) {
		year+=1;	s-=sb;	year+=s/ss;	s%=ss;
	}else if(s>59*sd)	s-=sd;
	
	for(;s>m[mon]*24*60*60;mon++)	s-=m[mon]*24*60*60;
	day+=s/sd; s%=sd;
	hour+=s/(60*60); s%=3600;
	min+=s/60; s%=60; sec=s;
	sec--;
	
	
	CIPSEND(" getTime",0);
    //printf("\n%d年%d月%d日%d时%d分%d秒\n",year,mon,day,hour,min,sec);
}

int RTC_Init(uint32_t counter,uint32_t prescaler,uint32_t alarm){
	NVIC_InitTypeDef NVIC_InitStruct;
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR|RCC_APB1Periph_BKP,ENABLE);	//使能PWR,BKP时钟
	PWR_BackupAccessCmd(ENABLE);	//使能后备寄存器访问
	
	if(BKP_ReadBackupRegister(BKP_DR1)!=0x5050){	//查看是否初始化，以0x5050(任意的)为初始化标志	
		int temp=0;
		//ESP8266_Init();
		RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR|RCC_APB1Periph_BKP,ENABLE);	//使能PWR,BKP时钟
		PWR_BackupAccessCmd(ENABLE);	//使能后备寄存器访问
		BKP_DeInit();	//后备区复位
		
		RCC_LSEConfig(RCC_LSE_ON);	//打开LSE时钟
		while(RCC_GetFlagStatus(RCC_FLAG_LSERDY)==RESET&&temp<250){	//等待时钟开启
			temp++;
			delay_ms(10);
		}
		if (temp>=250) {
			CIPSEND(" \nRTC ERROR\n",0);
			return 1;	//启动失败，晶振可能出问题了
		}
		LED_Star();
		RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);	//配置RTC时钟源为LSE
		RCC_RTCCLKCmd(ENABLE);	//时能RTC时钟
	
		RTC_WaitForLastTask();	//等待上次写入操作
		RTC_WaitForSynchro();	//等待寄存器同步
		RTC_ITConfig(RTC_IT_SEC, ENABLE);	//中断配置
		RTC_WaitForLastTask();	//等待上次写入操作
		RTC_EnterConfigMode();	//进入写入模式
		RTC_SetPrescaler(32767);	//设置预分频系数，输出1Hz的时钟
		RTC_WaitForLastTask();	//等待上次写入操作
		RTC_SetTime(2021,07,25,00,11,0);	//设置时间
		RTC_ExitConfigMode();	//退出写入操作
		
		BKP_WriteBackupRegister(BKP_DR1,0x5050);	//初始化结束，配置标志
	}
	else {
		RTC_WaitForSynchro();	//等待寄存器同步
		RTC_ITConfig(RTC_IT_SEC, ENABLE);	//中断配置
		RTC_WaitForLastTask();	//等待上次写入操作
	}
	CIPSEND(" \nRTC SUEESEE\n",0);

	NVIC_InitStruct.NVIC_IRQChannel=RTC_IT_SEC;
	NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=0;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority=2;
	NVIC_Init(&NVIC_InitStruct);
	
	//RTC_GetTime();
	return 0;
}

